home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-05-13 | 14.8 KB | 457 lines | [TEXT/KAHL] |
- // Bolo code (C) Stuart Cheshire <cheshire@cs.stanford.edu> 1987-1995.
- // All rights reserved. This code is owned by Stuart Cheshire and is donated
- // free of charge for non-commercial use. You may not use this code in any
- // product sold for commercial profit, except shareware priced at $25 or less.
-
- #include <Power.h>
- #include <EPPC.h>
- #include <Desk.h>
- #include <Scrap.h>
- #include <QuickDraw.h>
-
- #include "BrainFrame.h"
- #include "BF_Main.h"
- #include "BF_Globals.h"
- #include "BF_ResourceIDs.h"
- #include "BF_Events.h"
- #include "BF_Utils.h"
- #include "BF_IAC.h"
- #include "BF_Prefs.h"
- #include "BF_Interface.h"
-
- export MenuHandle AppleMenu = NULL;
- export MenuHandle FileMenu = NULL;
- export MenuHandle EditMenu = NULL;
- export MenuHandle BFMenu = NULL;
-
- export Boolean WNE_Busy; // set if not idle (ie stuff happening on screen)
- export Boolean WNE_Intensive; // means application temporarily wants Maximum CPU
-
- local Boolean newFrontWindow = TRUE;
- local Boolean MyFrontWindow = TRUE;
-
- // If File menu completely disabled, we have a movable modal dialog at the front
- #define MovableModalDialogActive ((*FileMenu)->enableFlags == 0)
-
- local ConnectionInfo *findconnection(WindowPtr win)
- {
- ConnectionInfo *conn = Connections;
- while(conn) if (conn->win == win) break; else conn = conn->next;
- if (!conn) conn = Connections;
- return(conn);
- }
-
- local void setmenus(void)
- {
- ConnectionInfo *conn = findconnection(FrontWindow());
- // if have a movable modal dialog at the front don't change menu settings
- if (MovableModalDialogActive) return;
-
- /***** Set items in the File menu *****/
-
- /***** Set items in the Edit menu *****/
-
- /***** Set items in the BrainFrame menu *****/
- CheckItem(BFMenu, bm_60, prefs.frametime == 1);
- CheckItem(BFMenu, bm_30, prefs.frametime == 2);
- CheckItem(BFMenu, bm_20, prefs.frametime == 3);
- CheckItem(BFMenu, bm_15, prefs.frametime == 4);
- }
-
- /*************************************************************************/
-
- export OSErr openwindow(void)
- {
- OSErr retcode;
- ConnectionInfo *conn = (ConnectionInfo *)NewPtr(sizeof(ConnectionInfo));
- if (!conn) return(1);
-
- retcode = PPCToolBoxConnect(conn);
- if (retcode) { DisposPtr((Ptr)conn); return(retcode); }
-
- retcode = BFInterfaceOpen(conn);
- if (retcode) { PPCToolBoxDisconnect(conn); DisposPtr((Ptr)conn); return(retcode); }
- conn->next = Connections;
- Connections = conn;
- CallBolo(conn, BoloResume);
- newFrontWindow = TRUE;
- return(noErr);
- }
-
- local void closewindow(WindowPtr win)
- {
- ConnectionInfo **conn = &Connections;
- while(*conn) if ((*conn)->win == win) break; else conn = &(*conn)->next;
- if (*conn)
- {
- ConnectionInfo *c = *conn;
- PPCToolBoxDisconnect(c);
- BFInterfaceClose(c);
- *conn = c->next;
- DisposePtr((Ptr)c);
- newFrontWindow = TRUE;
- }
- }
-
- local Boolean docommand(u_long com)
- {
- Boolean returncode = TRUE;
- short item = com & 0xFFFF, mark;
- MenuHandle mh = GetMHandle(com >> 16);
- Str255 menutext;
- WindowPtr fwin = FrontWindow();
- GetItem(mh, item, menutext);
- GetItemMark(mh, item, &mark);
- switch(com >> 16)
- {
- case 0 : break;
- case appleID:
- if (item > 1) OpenDeskAcc(menutext);
- else
- {
- short dummy;
- DialogPtr modal = OpenMovableModalDialog(MM_about);
- SetCursor(&qd.arrow);
- set_OutlineOK(modal, 2);
- DisableItem(AppleMenu, 1);
- MovableModalDialog(NULL, &dummy);
- EnableItem(AppleMenu, 1);
- CloseMovableModalDialog(modal);
- }
- break;
- case fileID:
- switch(item)
- {
- case fm_open: openwindow(); break;
- case fm_close: closewindow(fwin); break;
- case fm_quit: quitting = TRUE; returncode = FALSE; break;
- }
- break;
- case editID:
- // if desk accessory is frontmost, undo/cut/copy/paste/clear go to that
- if (item <= em_clear && ((WindowPeek)fwin)->windowKind != dialogKind)
- SystemEdit(item-1);
- else switch(item)
- {
- case em_undo: break;
- case em_cut: DlgCut(fwin); break;
- case em_copy: DlgCopy(fwin); break;
- case em_paste: DlgPaste(fwin); break;
- case em_clear: DlgDelete(fwin); break;
- }
- break;
- case BF_ID:
- switch(item)
- {
- case bm_60: prefs.frametime = 1; break;
- case bm_30: prefs.frametime = 2; break;
- case bm_20: prefs.frametime = 3; break;
- case bm_15: prefs.frametime = 4; break;
- }
-
- default: BFInterfaceMenu(findconnection(fwin), com >> 16, item); break;
- }
- save_prefs(); // If prefs have changed, write them to disk
- HiliteMenu(0); // zero means unhilite all hilited menus
- return(returncode);
- }
-
- local GDHandle findDominantDevice(Rect *theRect)
- {
- long sectArea, greatestArea = 0;
- GDHandle dominantGDevice = NULL, dev = GetDeviceList();
- while (dev) // for every device
- {
- if (TestDeviceAttribute(dev, screenDevice) && // that's an active screen
- TestDeviceAttribute(dev, screenActive))
- {
- Rect r;
- SectRect(theRect, &(**dev).gdRect, &r); // find out the intersection area
- sectArea = (long)(r.right - r.left) * (long)(r.bottom - r.top);
- if (greatestArea < sectArea) { greatestArea = sectArea; dominantGDevice = dev; }
- }
- dev = GetNextDevice(dev);
- }
- return(dominantGDevice);
- }
-
- #define topLeft(r) (((Point *) &(r))[0])
- #define botRight(r) (((Point *) &(r))[1])
-
- // The window will be zoomed to fill the screen it is already on,
- // subject to the size constraints of the Limits rectangle.
- // win = window to be zoomed
- // partCode = inZoomIn or inZoomOut
- // front = Bring window to front after zooming? (Normally TRUE)
- // Limits.top = minimum allowable window height
- // Limits.left = minimum allowable window width
- // Limits.bottom = maximum sensible window height + 1
- // Limits.right = maximum sensible window width + 1
- // Note: The maximums are actually one greater than the actual maximum allowed sizes,
- // for consistency with GrowWindow
- local void SmartZoomWindow(WindowPtr win, short partCode, Boolean front, const Rect *Limits)
- {
- // Zooming in is easy. Only zooming out needs extra smarts
- if (partCode == inZoomOut)
- {
- short hsize = Limits->right - 1;
- short vsize = Limits->bottom - 1;
- WindowPeek wp = (WindowPeek)win;
- Rect *windRect = &(*wp->strucRgn)->rgnBBox;
- Rect *zoomRect = &(*(WStateDataHandle)wp->dataHandle)->stdState;
- Rect globalPortRect = win->portRect;
- Rect target = qd.screenBits.bounds; // Start with a reasonable default
- target.top += GetMBarHeight();
- LocalToGlobal(&topLeft(globalPortRect)); // calculate the window's portRect
- LocalToGlobal(&botRight(globalPortRect)); // in global coordinates
-
- // *** TASK 1
- // Pick a monitor (if necessary) and work out the maximum allowable rectangle on it
- if (sysenvirons.hasColorQD)
- {
- GDHandle dev = findDominantDevice(windRect);
- if (dev)
- {
- target = (*dev)->gdRect;
- if (dev == GetMainDevice()) target.top += GetMBarHeight();
- }
- }
-
- // *** TASK 2
- // Reduce the logical target rectangle a little to allow for the frame
- // around the window, and a couple of pixels extra for aesthetic reasons
- target.top += 2 + (globalPortRect.top - windRect->top );
- target.left += 2 + (globalPortRect.left - windRect->left );
- target.bottom -= 1 + (windRect->bottom - globalPortRect.bottom);
- target.right -= 1 + (windRect->right - globalPortRect.right );
-
- // *** TASK 3
- // Make sure the target rectangle is big enough for the minimum size
- if (target.bottom < target.top + Limits->top ) target.bottom = target.top + Limits->top;
- if (target.right < target.left + Limits->left) target.right = target.left + Limits->left;
-
- // *** TASK 4
- // Make sure the desired (maximum) size fits within the target rectangle
- if (vsize > target.bottom - target.top) vsize = target.bottom - target.top;
- if (hsize > target.right - target.left) hsize = target.right - target.left;
-
- // *** TASK 5
- // Start off with a zoom rectangle obtained by simply resizing the window
- // in the current position
- zoomRect->top = globalPortRect.top;
- zoomRect->left = globalPortRect.left;
- zoomRect->bottom = globalPortRect.top + vsize;
- zoomRect->right = globalPortRect.left + hsize;
-
- // *** TASK 6
- // If Window is falls outside the limits, shift it the minimum amount to bring it inside
- if (zoomRect->top < target.top ) OffsetRect(zoomRect, 0, target.top - zoomRect->top);
- if (zoomRect->left < target.left ) OffsetRect(zoomRect, target.left - zoomRect->left, 0);
- if (zoomRect->bottom > target.bottom) OffsetRect(zoomRect, 0, target.bottom - zoomRect->bottom);
- if (zoomRect->right > target.right ) OffsetRect(zoomRect, target.right - zoomRect->right, 0);
- }
- ZoomWindow(win, partCode, front);
- }
-
- local Boolean checkmousedown(EventRecord *evrec)
- {
- static const Rect SizeLimits = { 80, 300, 0x7FFF, 0x7FFF };
- WindowPtr win;
- short partcode = FindWindow(evrec->where,&win);
- switch(partcode)
- {
- case inDesk : break;
- case inMenuBar : setmenus();
- return(docommand(MenuSelect(evrec->where))); break;
- case inSysWindow : SystemClick(evrec, win); break;
- case inContent :
- // In modal state, ignore clicks in windows
- if (MovableModalDialogActive) { SysBeep(30); break; }
- if (win != FrontWindow()) SelectWindow(win); //else clickedinwindow(evrec);
- break;
- case inDrag :
- // In modal state can only drag front window
- if (MovableModalDialogActive && win != FrontWindow()) SysBeep(30);
- else DragWindow(win, evrec->where, &qd.screenBits.bounds);
- break;
- case inGrow :
- {
- long newsize = GrowWindow(win, evrec->where, &SizeLimits);
- short *sp = (short*)&newsize;
- if (newsize) { SizeWindow(win, sp[1], sp[0], TRUE); BFInterfaceUpdateWindow(findconnection(win)); }
- }
- break;
- case inGoAway : closewindow(win); break;
- case inZoomIn :
- case inZoomOut :
- if (TrackBox(win, evrec->where, partcode))
- {
- SetPort(win);
- EraseRect(&win->portRect);
- SmartZoomWindow(win, partcode, TRUE, &SizeLimits);
- BFInterfaceUpdateWindow(findconnection(win));
- }
- break;
- }
- return(TRUE); // No quit -- continue running
- }
-
- local void activatewindow(WindowPtr win, Boolean activate)
- {
- ConnectionInfo *conn = findconnection(win);
- if (conn) CallBolo(conn, activate ? BoloResume : BoloSuspend);
- newFrontWindow = TRUE;
- }
-
- /*************************************************************************/
-
- // this ONLY gets called when one of my windows NEEDS to be updated.
- // ie. ((WindowPeek)win)->updateRgn) is non-empty.
- // foreground is called so that the map area is filled in immediately.
- // Note: Even if not drawing anything, must do BeginUpdate/EndUpdate to
- // poke the OS to let it know we have handled the updatewindow event.
- local void handle_update_event(WindowPtr win)
- {
- ConnectionInfo *conn = findconnection(win);
- GrafPtr savePort;
- GetPort(&savePort);
- SetPort(win);
- BeginUpdate(win);
- if (conn) BFInterfaceUpdateWindow(conn);
- EndUpdate(win);
- SetPort(savePort);
- }
-
- local void updatemenus(void)
- {
- Boolean bool = findconnection(FrontWindow()) != NULL;
- if (MyFrontWindow != bool)
- {
- MyFrontWindow = bool;
- if (MyFrontWindow) EnableItem(BFMenu, 0);
- else
- {
- int i;
- for (i = bm_60; i<=bm_end; i++) CheckItem(BFMenu, i, FALSE);
- DisableItem(BFMenu, 0);
- }
- DrawMenuBar();
- }
- }
-
- local void handle_null_event(void)
- {
- ConnectionInfo *conn = Connections;
- if (newFrontWindow) { updatemenus(); newFrontWindow = FALSE; }
- while (conn) { BFInterfaceIdle(conn); conn = conn->next; }
- }
-
- // handle_dialog_event handles mouse, key, redraw etc. events for Dialog Manager windows
- // It returns true if an item is hit in a frontmost (movable) modal dialog
-
- local Boolean handle_dialog_event(EventRecord *e, ModalFilterProcPtr FilterProc, short *item)
- {
- DialogPtr dp = FrontWindow();
- Boolean event = FALSE;
- *item = 0;
-
- // Install appropriate event filter if a modeless dialog is the front window
- //if (dp == window[DLG_MESSAGE]) FilterProc = message_dialog_filter;
- // ... etc. for other modeless dialogs, some day
-
- // See if FilterProc handles event
- if (FilterProc) event = FilterProc(dp, e, item);
-
- // Pass command keys through to docommand()
- if (!event && e->what == keyDown && e->modifiers & cmdKey)
- { setmenus(); docommand(MenuKey(e->message & charCodeMask)); return(FALSE); }
-
- // If not a special keyboard equivalent, see what DialogSelect makes of it
- // (DialogSelect handles update events, activate, deactivate etc.)
- if (!event) event = DialogSelect(e, &dp, item);
-
- // If some dialog button event has happened, see if it belongs to a modeless dialog
- if (event)
- {
- //if (dp == window[DLG_MESSAGE]) { message_dialog_event(*item); return(FALSE); }
- // ... etc. for other modeless dialogs, some day
- }
- return(event);
- }
-
- // Note:
- // Returns TRUE after an AppleEvent to indicate an item 'hit' so that control is
- // handed back to modal dialogs in case the AppleEvent has caused some change
- local Boolean handle_normal_event(EventRecord *e)
- {
- switch (e->what)
- {
- case mouseDown : checkmousedown(e); break;
- case keyDown : if (e->modifiers & cmdKey)
- {
- setmenus();
- docommand(MenuKey(e->message & charCodeMask));
- }
- break;
-
- case updateEvt : handle_update_event((WindowPtr)e->message); break;
-
- case activateEvt : activatewindow((WindowPtr)e->message, e->modifiers & activeFlag); break;
-
- case nullEvent :
- case mouseUp : case keyUp : case autoKey :
- case diskEvt : case networkEvt : case driverEvt :
- case app1Evt : case app2Evt : case app3Evt : break; // these never happen
- case osEvt : if (e->message >> 24 == suspendResumeMessage)
- {
- frontapp = e->message & resumeFlag;
- if (frontapp)
- {
- SetCursor(&qd.arrow);
- TEFromScrap();
- activatewindow(FrontWindow(), 1);
- }
- else
- {
- ZeroScrap();
- TEToScrap();
- activatewindow(FrontWindow(), 0);
- }
- }
- break;
- case kHighLevelEvent: AEProcessAppleEvent(e); return(TRUE);
- }
- return(FALSE);
- }
-
- // If handle_next_event is being used to handle events for a movable modal dialog, then
- // the FilterProc will be non-null and MacMainLoop will return TRUE if an item is hit
-
- export Boolean handle_next_event(ModalFilterProcPtr FilterProc, short *item)
- {
- static u_long busytime, last_null;
- u_long this_time = TickCount();
- u_long sleep;
- EventRecord e;
- short dummy;
- if (!item) item = &dummy;
- *item = 0;
-
- if (WNE_Busy) { WNE_Busy = FALSE; busytime = this_time; }
- if (WNE_Intensive) { WNE_Intensive = FALSE; sleep = 0; }
- else
- {
- sleep = (this_time - busytime) >> 6;
- if (sleep < prefs.frametime) sleep = prefs.frametime;
- else if (frontapp && sleep > 6) sleep = 6; // max is 1/10 sec in foreground
- else if (sleep > 12) sleep = 12; // or 1/5 sec in background
- if (sleep < this_time - last_null) sleep = 0; else sleep -= this_time - last_null;
- }
- WaitNextEvent(everyEvent, &e, sleep, NULL);
- if (e.what == nullEvent && this_time != last_null)
- { last_null = this_time; handle_null_event(); }
-
- if (IsDialogEvent(&e)) return(handle_dialog_event(&e, FilterProc, item));
- else return(handle_normal_event(&e));
- }
-